//MCU = atmega88
//F_CPU = defined in makefile
//hfuse: DF
//lfuse: 62
//efuse: 1

#include <avr/io.h> 
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h> 

#include <avr/pgmspace.h>   /* required by usbdrv.h */
#include "usbdrv.h"
#include "requests.h"       /* The custom request numbers we use */

//some useful stuff
#define SET(x,y) (x|=(1<<y))
#define CLR(x,y) (x&=(~(1<<y)))
#define CHK(x,y) (x&(1<<y)) 
#define TOG(x,y) (x^=(1<<y))

#define ENABLE_BOOST SET(PORTD, PD7)
#define DISABLE_BOOST CLR(PORTD, PD7)
#define ENABLE_USBLED SET(PORTB, PB0);
#define DISABLE_USBLED CLR(PORTB, PB0);

#include "timers.c"

#define SAMPLE_COUNT 280
//--------- GLOBALS ----------------
typedef uint8_t sample_t;
volatile sample_t samples[SAMPLE_COUNT];
volatile uint16_t sample_index = SAMPLE_COUNT;
volatile uint16_t boost_index = 70;
//-----------------------------------------------------------------------------
//Functions
//-----------------------------------------------------------------------------
PROGMEM const char usbHidReportDescriptor[22] = {    /* USB report descriptor */
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x00,                    //   USAGE (Undefined)
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
    0xc0                           // END_COLLECTION
};

#define USB_MSG_LENGTH SAMPLE_COUNT
usbMsgLen_t usbFunctionSetup(uchar data[8]){
	usbRequest_t    *rq = (void *)data;
	if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){
		if(rq->bRequest == CUSTOM_RQ_GET_DATA){
			static uchar dataBuffer[USB_MSG_LENGTH];
            uint16_t i;
            for(i=0;i<USB_MSG_LENGTH;i++){
                dataBuffer[i] = samples[i];
            }
            usbMsgPtr = dataBuffer;
			return USB_MSG_LENGTH;                   
		}else if(rq->bRequest == CUSTOM_RQ_NEXT_PULSE){
            CLR(USB_INTR_ENABLE, USB_INTR_ENABLE_BIT);
            TOG(PORTB, PB1);
            //set prescaler
            ADCSRA &= 0xF8; //clear last 3 bits
            ADCSRA |= (1<<ADSC) |  rq->wValue.bytes[0];//set prescaler to wval
            sample_index = 0xffff;
			startBurst();
            return(1);
        }else if(rq->bRequest == CUSTOM_RQ_TOGGLE_BURSTS){
	        if((TCCR0B & 0x07) >= 5) TCCR0B = 0xF8;
            else TCCR0B = 0xF8 | 5;
            return(0);
        }
	}
	return(0);
}


//-----------------------------------------------------------------------------
//MAIN
//-----------------------------------------------------------------------------
//usb initialization
int main() {
    wdt_enable(WDTO_1S); //set watchdog to 1 second
    usbInit();
    //disconnect, wait a bit and reconnect. I didn't think of this
    //it's recommended practice apparently
    usbDeviceDisconnect();
    register uint8_t i=0;
    while(--i){
        wdt_reset();
        _delay_ms(1);
    }
    usbDeviceConnect();
    sei(); //enable all interrupts

    //adc init
    //use interrupts, prescaler bits at 0, ref is avcc
    ADMUX |= (1<<REFS0) | (1<<ADLAR);
    ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | 4;

    DIDR0 = 
        (1<<ADC5D) | (1<<ADC4D) | (1<<ADC3D) |
        (1<<ADC2D) | (1<<ADC1D) | (1<<ADC0D);

    //TIMERS
    init_timers(0,200); //0 for clock since we're doing startBurst ourselves
                        //use 5 otherwise

    //other ports
    SET(DDRD, PD7);//boost amp
    SET(DDRB, PB0); //usb led
    DISABLE_BOOST;
    ENABLE_USBLED;
    SET(DDRB, PB1);

//-----------------------------------------------------------------------------
//MAIN LOOP
//-----------------------------------------------------------------------------
while(1){
	wdt_reset();
    //only do usb if weve filled an entire buffer
    //and set the indicator led
    if(sample_index >= SAMPLE_COUNT){   
        usbPoll();
	}
	
	
	
	}//main loop end
}//main end


//------------------------------------------------
//ADC VECTOR
//------------------------------------------------
ISR(ADC_vect){
	//store in buffer, start new conversion if the buffer is not full
	sample_index++;
    if(sample_index == boost_index){
        //ENABLE_BOOST;
    }
    if(sample_index < SAMPLE_COUNT){
        //read ADCL and ADCH (we only need H but both need to be read
        // to unlock the registers for the next conversion
        samples[sample_index] = ADCL; //no fancy compression yet
        samples[sample_index] = ADCH;         
        SET(ADCSRA, ADSC);
    }else{
        //indicate ready for usb
        sample_index = SAMPLE_COUNT;
        DISABLE_BOOST;
        SET(USB_INTR_ENABLE, USB_INTR_ENABLE_BIT);
    }
}
